/** 
 * UIMA Connectors
 * Copyright (C) 2010-12  Nicolas Hernandez
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *     http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */

package fr.univnantes.lina.ftbcleaner;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;

import fr.univnantes.lina.ftbcleaner.WordAttributes;
import fr.univnantes.lina.ftbcleaner.WordCatFormOtherCounters;
import fr.univnantes.lina.ftbcleaner.WordForms;
import fr.univnantes.lina.javautil.CollectionUtilities;
import fr.univnantes.lina.mlnlp.connectors.ftb.FTBXMLSchema;


/**
 * 
 * Collect some single word properties
 * word2CatMap, wordCat2SubcatMap...
 * 
 * And build a list of sw not amalgame with for each one the textContent, cat, subcat, lemma, and mph  
 *  (ArrayList<ArrayList<string>>)
 *  in addition 
 *     
 * @author hernandez
 *
 */
public  class FTBXMLSingleWordSaxHandler extends DefaultHandler {

	/*
	 * 
	 */

	//private Boolean debug = true;

	/*
	 * 
	 */


	/*
	 * 
	 */


	/**
	 * attr compound
	 */
	private Boolean isMultiWord = false;

	/**
	 * isMultiWord and depth > 1
	 */
	private Boolean isPartOfMultiWord = false;

	/**
	 * normalize-space(.)=''
	 */
	//private Boolean isAmalgame = true;

	/**
	 * (not(@compound) and not(PartOf)) or (not(@compound) and (@cat))
	 */
	private Boolean isSingleWord = false;

	/**
	 * List of properties' single word occurrences
	 */
	//	List<List<String>> singleWordOccPropertiesList ;
	List<WordAttributes> singleWordOccAttributesList ;


	/**
	 * gives for each given cat if some words occur with subcat, lemma, or mph
	 */
	Set<String> subcatAttributeSet;
	Set<String> lemmaAttributeSet;
	Set<String> mphAttributeSet;


	/*
	 * temporary variables
	 */

	/**
	 * 
	 */
	private WordAttributes currentSingleWordOccAttributes;
	
	/**
	 * Curseur de la pile d'éléments en cours
	 */
	private int elementOffsetStackCursor = -1;

	/**
	 * 
	 */
	private int depth = 0;



	/**
	 * 
	 */
	private WordForms aWordForms;

	/*
	 * ACCESSORS
	 */

	/**
	 * 
	 */
	public List<WordAttributes> getSingleWordOccAttributesList() {
		return this.singleWordOccAttributesList;
	}

	/**
	 * 
	 */
	public Boolean hasSubcatAttribute(String cat) {
		return this.subcatAttributeSet.contains(cat);
	}
	/**
	 * 
	 */
	public Boolean hasLemmaAttribute(String cat) {
		return this.lemmaAttributeSet.contains(cat);
	}
	/**
	 * 
	 */
	public Boolean hasMphAttribute(String cat) {
		return this.mphAttributeSet.contains(cat);
	}

	/*
	 * 
	 */

	/**
	 * Constructor
	 * Comes with no parameter
	 */
	public FTBXMLSingleWordSaxHandler(WordForms aWordOccurrences) {		
		this.singleWordOccAttributesList  = new ArrayList<WordAttributes>();

		this.subcatAttributeSet = new HashSet<String>() ;
		this.lemmaAttributeSet = new HashSet<String>() ;
		this.mphAttributeSet = new HashSet<String>() ;

		this.aWordForms = aWordOccurrences;


	}


	/*
	 * 
	 */



	/**
	 * 
	 */
	private void incrementOccurrenceCounters(WordForms aWordForms, WordAttributes aWordAttributes) {

		// Count the cat occurrences for a given word
		CollectionUtilities.incrementKeyCounter(
				aWordForms.getWordFormCatCounter(aWordAttributes.getWord()).getCatMap(), 
				aWordAttributes.getCat());

		// Count the subcat occurrences depending on the word forms + cat
		String key = aWordAttributes.getWord()+" "+ aWordAttributes.getCat();
		WordCatFormOtherCounters awcfoc = aWordForms.getWordCatFormOtherCounters(key);
		Map<String,Integer> awcfocSubcatMap= awcfoc.getSubcatMap();
		CollectionUtilities.incrementKeyCounter(
				awcfocSubcatMap, 
				aWordAttributes.getSubcat());

		// Count the lemma occurrences depending on the word forms + cat
		CollectionUtilities.incrementKeyCounter(
				aWordForms.getWordCatFormOtherCounters(aWordAttributes.getWord()+" "+ aWordAttributes.getCat()).getLemmaMap(), 
				aWordAttributes.getLemma());

		// Count the mph occurrences depending on the word forms + cat
		CollectionUtilities.incrementKeyCounter(
				aWordForms.getWordCatFormOtherCounters(aWordAttributes.getWord()+" "+ aWordAttributes.getCat()).getMphMap(), 
				aWordAttributes.getMph());
	}


	/*
	 * 
	 */

	/**
	 * 
	 */
	public void startDocument() throws SAXException {
		/*if (debug) {
			System.out.println ("------------------------------------------------------------------------------------------");
			System.out.println ("Debug: startDocument");
		}*/
	}

	/**
	 * 
	 */
	public void endDocument() throws SAXException {
		Iterator<String> word2CatMapIterator = aWordForms.getWords().iterator();

		while (word2CatMapIterator.hasNext()) {
			String wordString = word2CatMapIterator.next();
			Map<String,Integer> catOccMap = aWordForms.getWordFormCatCounter(wordString).getCatMap();
			//word2CatMap.get(wordString);

			if (catOccMap != null) {
				TreeMap<String,Integer> aSortedMWECatintsMap = CollectionUtilities.sortStringIntegerHashMapByValue (catOccMap);
				String firstCat = aSortedMWECatintsMap.firstKey();

				aWordForms.getWordFormCatCounter(wordString).setCatMap(aSortedMWECatintsMap);

				// which subcat is the most sailant for the couple word cat ?
				//		String key = wordString+" "+firstCat;
				//System.err.println("Debug: wordString+' '+aSortedMWECatintsMap.get(aSortedMWECatintsMap.firstKey()) = "+ key);
				TreeMap<String,Integer> aSortedMWESubcatintsMap = CollectionUtilities.sortStringIntegerHashMapByValue (aWordForms.getWordCatFormOtherCounters(wordString+" "+firstCat).getSubcatMap());
				aWordForms.getWordCatFormOtherCounters(wordString+" "+firstCat).setSubcatMap(aSortedMWESubcatintsMap);

				TreeMap<String,Integer> aSortedMWEMemmasMap = CollectionUtilities.sortStringIntegerHashMapByValue (aWordForms.getWordCatFormOtherCounters(wordString+" "+firstCat).getLemmaMap());
				aWordForms.getWordCatFormOtherCounters(wordString+" "+firstCat).setLemmaMap(aSortedMWEMemmasMap);

				TreeMap<String,Integer> aSortedMWEMphsMap = CollectionUtilities.sortStringIntegerHashMapByValue (aWordForms.getWordCatFormOtherCounters(wordString+" "+firstCat).getMphMap());
				aWordForms.getWordCatFormOtherCounters(wordString+" "+firstCat).setMphMap(aSortedMWEMphsMap);

			}
			else {
				System.err.println("Warning: the current word part of a multi word does not occur as a single word");
			}
		}
	}

	/**
	 * Start Element
	 * localName - The local name (without prefix), or the empty string if Namespace processing is not being performed.
	 * qName - The qualified name (with prefix), or the empty string if qualified names are not available.
	 */
	public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {

		// 
		if (qName.equalsIgnoreCase(FTBXMLSchema.WORD_ELEMENT)) {

			//
			depth++;

			// 
			if (attributes.getValue (FTBXMLSchema.COMPOUND_ATTRIBUTE) != null) {
				isMultiWord = true;
			}
			else if (isMultiWord) {
				isPartOfMultiWord = true;
			}
			else {
				isSingleWord = true;
				currentSingleWordOccAttributes = new WordAttributes();
				String cat = attributes.getValue(FTBXMLSchema.CAT_ATTRIBUTE);
				String subcat = attributes.getValue(FTBXMLSchema.SUBCAT_ATTRIBUTE);
				String lemma = attributes.getValue(FTBXMLSchema.LEMMA_ATTRIBUTE);
				String mph = attributes.getValue(FTBXMLSchema.MPH_ATTRIBUTE);

				currentSingleWordOccAttributes.setCat(cat == null ? "" : cat);
				currentSingleWordOccAttributes.setSubcat(subcat == null ? "" : subcat);
				currentSingleWordOccAttributes.setLemma(lemma == null ? "" : lemma);
				currentSingleWordOccAttributes.setMph(mph == null ? "" : mph);

				/*currentSingleWordAttributesList.add(cat == null ? "" : cat);
				currentSingleWordAttributesList.add(subcat == null ? "" : subcat);
				currentSingleWordAttributesList.add(lemma == null ? "" : lemma);
				currentSingleWordAttributesList.add(mph == null ? "" : mph);
				 */
			}
			//isAmalgame = true;
		}

	}

	/**
	 * on est en présence de characters
	 */
	public void characters(char[] ch, int start, int length) throws SAXException {

		if (isSingleWord) {
			// debug
			/*if (debug) {
				// affichage de la chaine de caractères ainsi que son début et sa longueur
				for (int indent=0 ; indent < elementOffsetStackCursor ; indent++) System.out.print ("--");
				System.out.print("Debug: characters ch>");
				for (int i =start ; i < start+length  ; i++) {System.out.print(ch[i]);}
				System.out.println("< begin>"+start+"< length>"+length+"<");
			}*/	
			String content = new String(ch).substring(start, start+length).trim();
			//if (content.equalsIgnoreCase("")) isAmalgame = true;
			//currentSingleWordAttributesList.add(0, new String(ch).trim());
			//currentSingleWordAttributesList.add(content);
			//System.out.println("Debug: currentSingleWordAttributes.setWord(content) "+ content);

			currentSingleWordOccAttributes.setWord(content);

		}
		// if characters is called then
		//isAmalgame = false;
	}


	/**
	 *  End  element
	 */
	public void endElement(String uri, String localName, String qName) throws SAXException {

		// 
		if (qName.equalsIgnoreCase(FTBXMLSchema.WORD_ELEMENT)) {

			// debug
			/*
			if (debug) {
				for (int indent=0 ; indent < elementOffsetStackCursor ; indent++) {System.out.print ("--");}
				System.out.println ("Debug: endElement tag>"+qName+"<");
			}*/

			depth--;

			if (isMultiWord) isPartOfMultiWord = false;
			else if (isSingleWord) {

				//if (!isAmalgame)
				//System.out.println ("Debug: currentSingleWordAttributes.getWord() "+currentSingleWordAttributes.getWord());


				//if (!((String)currentSingleWordOccAttributes.getWord()).equalsIgnoreCase("")) {

					//
					//	singleWordOccPropertiesList.add(currentSingleWordAttributesList);
					singleWordOccAttributesList.add(currentSingleWordOccAttributes);
					//System.out.println ("Debug: singleWordOccAttributesList.add(currentSingleWordAttributes)");
					// compute stats
					/*incrementOccurrenceCounters(
							(String)currentSingleWordAttributesList.get(4), // word
							(String)currentSingleWordAttributesList.get(0), // cat
							(String)currentSingleWordAttributesList.get(1), // subcat
							(String)currentSingleWordAttributesList.get(2), // lemma
							(String)currentSingleWordAttributesList.get(3)); // mph
					 */
					incrementOccurrenceCounters( aWordForms,  currentSingleWordOccAttributes);

				//}
			}
			if (depth==0) isMultiWord = false;
			isSingleWord = false;


		}
		//isAmalgame = true;
	}


	/**
	 * 

	public void ignorableWhitespace(char[] ch, int start, int length) throws SAXException {
		if (debug) {
			for (int indent=0 ; indent < elementOffsetStackCursor ; indent++) {System.out.print ("--");}
			System.out.println ("Debug: ignorableWhitespace >"+new String(ch)+"< ");
		}

		if (insideTextTag) {
			if (setPlainTextCursorsRelativelyToXmlTagCursors) detaggedText.append(ch, start, length);        
		}
	}
	 */

}